#include "UniformCrossover.h"
#include "../../Solution/BitEncoded/BitEncodedSolution.h"
#include "../../Solution/PermutationEncoded/PermutationEncodedSolution.h"
#include "../../Solution/ValueEncoded/ValueEncodedSolution.h"
#include "../../Random/MyRandom.h"
#include "../../Exception/GA_Exception.h"
#include "../../Random/MyRandom.h"
#include <algorithm>

template <typename T>
UniformCrossover<T>::UniformCrossover()
{
    throw Unsupported_template_exception();
}

template <typename T>
void UniformCrossover<T>::setProbability(double newProbability)
{
    if (newProbability > 0.0 && newProbability < 1.0) {
        probability = newProbability;
    }
    else {
        //TODO: I should probably throw an exception here, instead of quietly failing
    }
}

UniformCrossover<PermutationEncodedSolution>::UniformCrossover()
{
    probability = 0.5;
}

UniformCrossover<BitEncodedSolution>::UniformCrossover()
{
    probability = 0.5;
}

UniformCrossover<ValueEncodedSolution<int> >::UniformCrossover()
{
    probability = 0.5;
}

UniformCrossover<PermutationEncodedSolution>::UniformCrossover(double newProbability)
{   
    probability = 0.5;
    setProbability(newProbability);
}

UniformCrossover<BitEncodedSolution>::UniformCrossover(double newProbability)
{
    probability = 0.5;
    setProbability(newProbability);
}

UniformCrossover<ValueEncodedSolution<int> >::UniformCrossover(double newProbability)
{
    probability = 0.5;
    setProbability(newProbability);
}

void UniformCrossover<PermutationEncodedSolution>::cross(Solution *parent1, Solution *parent2, Solution* &child1, Solution* &child2)
{
    //I don't know how a uniform crossover in a permutation encoded solution should work
    //TODO: Go figure out how this should work.
    throw Unsupported_template_exception();
} 

void UniformCrossover<BitEncodedSolution>::cross(Solution *parent1, Solution *parent2, Solution* &child1, Solution* &child2)
{
    BitEncodedSolution* besParent1 = (BitEncodedSolution*) parent1;
    BitEncodedSolution* besParent2 = (BitEncodedSolution*) parent2;
    BitEncodedSolution* besTmp1 = (BitEncodedSolution*) besParent1->clone();
    BitEncodedSolution* besTmp2 = (BitEncodedSolution*) besParent2->clone();
    
    unsigned int solSize = min(besTmp1->getSize(), besTmp2->getSize());
    
    //for each element in the solution...
    for (unsigned int i = 0; i < solSize; ++i) {
        //...randomly decide if we should swap that element in the solutions
        if (MyRandom::randDbl() <= probability) {
            besTmp1->setBit(i, besParent2->getBit(i));
            besTmp2->setBit(i, besParent1->getBit(i));
        }
    }
    
    child1 = besTmp1;
    child2 = besTmp2;
} 

void UniformCrossover<ValueEncodedSolution<int> >::cross(Solution *parent1, Solution *parent2, Solution* &child1, Solution* &child2)
{
    //TODO: Is this crossover done right for ValueEncoded solutions?
    ValueEncodedSolution<int>* vesParent1 = (ValueEncodedSolution<int>*) parent1;
    ValueEncodedSolution<int>* vesParent2 = (ValueEncodedSolution<int>*) parent2;    
    ValueEncodedSolution<int>* vesTmp1 = (ValueEncodedSolution<int>*) parent1->clone();
    ValueEncodedSolution<int>* vesTmp2 = (ValueEncodedSolution<int>*) parent2->clone();
    
    unsigned int solSize = min(vesTmp1->getSize(), vesTmp2->getSize());
    
    //for each element in the solution...
    for (unsigned int i = 0; i < solSize; ++i) {
        //...randomly decide if we should swap that element in the solutions
        if (MyRandom::randDbl() <= probability) {
            (*vesTmp1)[i] = (*vesParent2)[i];
            (*vesTmp2)[i] = (*vesParent1)[i];
        }
    }
    
    child1 = vesTmp1;
    child2 = vesTmp2;
} 

//instruct the compiler to pre-generate some templated classes at compile time
template class UniformCrossover<BitEncodedSolution>;
template class UniformCrossover<PermutationEncodedSolution>;
template class UniformCrossover<ValueEncodedSolution<int> >;
